home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1997 December
/
CHIPNET Aralık 1997.iso
/
linux
/
redhat
/
misc
/
src
/
init
/
init.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-11
|
14KB
|
629 lines
/*
* init.c
*
* This is the install type init
*
* Erik Troan (ewt@redhat.com)
*
* Copyright 1996 Red Hat Software
*
* This software may be freely redistributed under the terms of the GNU
* public license.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <ctype.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/if.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#ifdef __alpha__
#include <sys/reboot.h>
#endif
/*
* this needs to handle the following cases:
*
* 1) run from a CD root filesystem
* 2) run from a read only nfs rooted filesystem
* 3) run from a floppy
* 4) run from a floppy that's been loaded into a ramdisk
*
*/
int testing;
#define __LIBRARY__
#include <linux/unistd.h>
#ifndef __alpha__
# define __NR_sys_syslog __NR_syslog
_syscall3(int,syslog,int, type, char *, buf, int, len);
#else
# define syslog klogctl
#endif
void fatal_error(int usePerror) {
if (usePerror)
perror("failed:");
else
fprintf(stderr, "failed.\n");
fprintf(stderr, "\nI can't recover from this.\n");
while (1) ;
}
int doMke2fs(char * device, char * size) {
char * args[] = { "/usr/bin/mke2fs", NULL, NULL, NULL };
int pid, status;
args[1] = device;
args[2] = size;
if (!(pid = fork())) {
/* child */
execv("/usr/bin/mke2fs", args);
fatal_error(1);
}
wait(&status);
return 0;
}
int hasNetConfiged(void) {
int rc;
int s;
struct ifconf configs;
struct ifreq devs[10];
#ifdef __i386__
return 0;
#endif
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("socket");
return 0;
} else {
/* this is just good enough to tell us if we have anything
configured */
configs.ifc_len = sizeof(devs);
configs.ifc_buf = (void *) devs;
rc = ioctl(s, SIOCGIFCONF, &configs);
if (rc < 0) {
perror("SIOCGIFCONF");
return 0;
}
if (configs.ifc_len == 0) {
return 0;
}
return 1;
}
return 0;
}
void doklog(char * fn) {
fd_set readset, unixs;
int in, out, i;
size_t s;
int sock;
struct sockaddr_un sockaddr;
char buf[1024];
int readfd;
in = open("/proc/kmsg", O_RDONLY);
if (in < 0) {
perror("open /proc/kmsg");
return;
}
out = open(fn, O_WRONLY);
if (out < 0) {
printf("couldn't open %s for syslog -- trying /tmp/syslog\n", fn);
out = open("/tmp/syslog", O_WRONLY | O_CREAT | 0644);
if (out < 0) {
perror("open kmsg log");
close(in);
return;
}
}
/* if we get this far, we should be in good shape */
if (fork()) {
/* parent */
close(in);
close(out);
return;
}
close(0); close(1); close(2);
/* now open the syslog socket */
sockaddr.sun_family = AF_UNIX;
strcpy(sockaddr.sun_path, "/dev/log");
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 1) {
write(out, "socket error\n", 13);
}
if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) +
strlen(sockaddr.sun_path))) {
write(out, "bind error\n", 11);
}
chmod("/dev/log", 0666);
if (listen(sock, 5)) {
write(out, "listen error\n", 13);
}
syslog(8, NULL, 1);
FD_ZERO(&unixs);
while (1) {
memcpy(&readset, &unixs, sizeof(unixs));
FD_SET(sock, &readset);
FD_SET(in, &readset);
i = select(FD_SETSIZE, &readset, NULL, NULL, NULL);
if (i <= 0) continue;
if (FD_ISSET(in, &readset)) {
i = read(in, buf, sizeof(buf));
if (i > 0) write(out, buf, i);
}
for (readfd = 0; readfd < FD_SETSIZE; ++readfd) {
if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) {
i = read(readfd, buf, sizeof(buf));
if (i > 0) {
write(out, buf, i);
write(out, "\n", 1);
} else if (i == 0) {
/* socket closed */
close(readfd);
FD_CLR(readfd, &unixs);
}
}
}
if (FD_ISSET(sock, &readset)) {
i = sizeof(sockaddr);
readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
if (readfd < 0) {
/*write(out, "error in accept\n", 16);*/
} else {
FD_SET(readfd, &unixs);
}
}
}
}
#if defined(__alpha__)
char * findKernel(void) {
char * dev, * file;
struct stat sb;
dev = getenv("bootdevice");
file = getenv("bootfile");
if (!dev || !file) {
printf("I can't find your kernel. When you are booting"
" from a CDROM, you must pass\n");
printf("the bootfile argument to the kernel if your"
" boot loader doesn't do so automatically.\n");
printf("\n");
printf("You should now reboot your system and try "
"again\n");
while (1) ;
}
if (!strcmp(dev, "fd0")) {
if (!strcmp(file, "vmlinux.gz")) {
printf("The kernel on a boot floppy must be named vmlinux.gz. "
"You\n");
printf("are using a kernel named %s instead. You'll have "
"to\n", file);
printf("fix this and try again.\n");
while (1) ;
}
return NULL;
} else {
if (stat(file, &sb)) {
printf("I can't find your kernel. When you are booting"
" from a CDROM, you must pass\n");
printf("the bootfile argument to the kernel if your"
" boot loader doesn't do so automatically.\n");
printf("\n");
printf("You should now reboot your system and try "
"again\n");
while (1) ;
}
return file;
}
}
#endif
int setupTerminal(int fd) {
struct winsize winsize;
if (ioctl(fd, TIOCGWINSZ, &winsize)) {
printf("failed to get winsize");
fatal_error(1);
}
winsize.ws_row = 24;
winsize.ws_col = 80;
if (ioctl(fd, TIOCSWINSZ, &winsize)) {
printf("failed to set winsize");
fatal_error(1);
}
putenv("TERM=vt100");
return 0;
}
void unmountFilesystems(void) {
int fd, size;
char buf[65535]; /* this should be big enough */
char * chptr, * start;
struct {
char * name;
int len;
} filesystems[500], tmp;
int numFilesystems = 0;
int i, j;
fd = open("/proc/mounts", O_RDONLY);
if (fd < 1) {
perror("failed to open /proc/mounts");
sleep(2);
return;
}
size = read(fd, buf, sizeof(buf) - 1);
buf[size] = '\0';
close(fd);
chptr = buf;
while (*chptr) {
while (*chptr != ' ') chptr++;
chptr++;
start = chptr;
while (*chptr != ' ') chptr++;
*chptr++ = '\0';
filesystems[numFilesystems].name = start;
filesystems[numFilesystems].len = strlen(start);
numFilesystems++;
while (*chptr != '\n') chptr++;
chptr++;
}
/* look ma, a *bubble* sort */
for (i = 0; i < (numFilesystems - 1); i++) {
for (j = i; j < numFilesystems; j++) {
if (filesystems[i].len < filesystems[j].len) {
tmp = filesystems[i];
filesystems[i] = filesystems[j];
filesystems[j] = tmp;
}
}
}
/* -1 because the last one will always be '/' */
for (i = 0; i < numFilesystems - 1; i++) {
printf("\t%s", filesystems[i].name); fflush(stdout);
if (!testing) {
if (umount(filesystems[i].name)) {
printf(" failed: %s", strerror(errno));
}
}
printf("\n");
}
}
void readargs(int * isRescue, int * isSerial) {
char buf[512];
int fd;
int size;
int done = 0;
char * start, * end;
printf("opening /proc/cmdline... "); fflush(stdout);
if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) fatal_error(1);
size = read(fd, buf, sizeof(buf) - 1);
buf[size] = '\0';
close(fd);
printf("done\n");
printf("checking command line arguments..."); fflush(stdout);
start = buf;
while (!done) {
while (*start && isspace(*start)) start++;
if (!(*start)) break;
end = start;
while (*end && !isspace(*end)) end++;
if (!*end) done = 1;
*end = '\0';
if (!strcmp(start, "auto") ||
!strncmp(start, "BOOT_IMAGE", 10) ||
!strncmp(start, "initrd=", 7) ||
!strncmp(start, "bootdevice=", 11) ||
!strncmp(start, "bootfile=", 9) ||
!strcmp(start, "ro") ||
!strncmp(start, "root=", 5) ||
!strncmp(start, "load_ramdisk", 12) ||
!strncmp(start, "prompt_ramdisk", 14)) {
/* lilo does this for us -- we don't care */
} else if (!strcmp(start, "rescue")) {
printf("\n\trescue disk mode enabled"); fflush(stdout);
*isRescue = 1;
} else if (!strcmp(start, "serial")) {
printf("\n\tserial mode enabled"); fflush(stdout);
fflush(stdout);
*isSerial = 1;
} else {
printf("\n\tunknown option '%s'!", start); fflush(stdout);
sleep(5);
}
start = end + 1;
}
printf("\n");
}
void main(void) {
pid_t installpid, childpid;
int waitStatus;
int fd;
int nfsRoot = 0;
int roRoot = 0;
int cdRoot = 0;
int isRescue = 0;
int isSerial = 0;
int doReboot = 0;
int doShutdown =0;
#ifdef __alpha__
char * kernel;
#endif
/* getpid() != 1 should work, by linuxrc tends to get a larger pid */
testing = (getpid() > 50);
if (!testing) {
/* turn off screen blanking */
printf("\033[9;0]");
printf("\033[8]");
}
printf("Red Hat install init version %s starting\n", VERSION);
putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:"
"/mnt/bin:/mnt/usr/bin");
putenv("LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib");
putenv("HOME=/");
printf("mounting /proc filesystem... "); fflush(stdout);
if (!testing) {
if (mount("/proc", "/proc", "proc", 0, NULL))
fatal_error(1);
}
readargs(&isRescue, &isSerial);
if (isSerial) {
fd = open("/dev/cua0", O_RDWR);
if (fd < 0) {
printf("failed to open /dev/cua0");
fatal_error(1);
}
write(fd, "Switching to serial console...", 29);
/* gulp */
fflush(stdout);
fflush(stderr);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
printf("done\n\n"); fflush(stdout);
printf("Red Hat install init version %s using a serial console\n",
VERSION);
printf("remember, cereal is an important part of a nutritionally "
"balanced breakfast.\n\n");
setupTerminal(0);
close(fd);
}
sethostname("localhost", 9);
printf("done\n");
if (!testing)
doklog("/dev/tty4");
printf("checking for NFS root filesystem..."); fflush(stdout);
if (hasNetConfiged()) {
printf("yes\n");
roRoot = nfsRoot = 1;
} else {
printf("no\n");
}
if (!nfsRoot) {
printf("trying to remount root filesystem read write... ");
if (mount("/", "/", NULL, MS_REMOUNT | MS_MGC_VAL, NULL)) {
printf("failed (but that's okay)\n");
roRoot = 1;
} else {
printf("done\n");
/* 2.0.18 (at least) lets us remount a CD r/w!! */
printf("checking for writeable /tmp... ");
fd = open("/tmp/tmp", O_WRONLY | O_CREAT, 0644);
if (fd < 0) {
printf("no (probably a CD rooted install)\n");
roRoot = 1;
} else {
close(fd);
unlink("/tmp/tmp");
printf("yes\n");
}
}
}
if (roRoot) {
printf("creating 100k of ramdisk space... "); fflush(stdout);
if (doMke2fs("/dev/ram", "100"))
fatal_error(0);
printf("done\n");
printf("mounting /tmp from ramdisk... "); fflush(stdout);
if (mount("/dev/ram", "/tmp", "ext2", 0, NULL))
fatal_error(1);
printf("done\n");
if (!nfsRoot) cdRoot = 1;
}
/* Now we have some /tmp space set up, and /etc and /dev point to
it. We should be in pretty good shape. */
/* Go into normal init mode - keep going, and then do a orderly shutdown
when:
1) /bin/install exits
2) we receive a SIGHUP
*/
printf("running install...\n");
if (!(installpid = fork())) {
/* child */
if (nfsRoot) {
symlink("/", "/tmp/rhimage");
symlink("/", "/tmp/image");
execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", "--method",
"nfs", isRescue ? "--rescue" : NULL, NULL);
} else if (cdRoot) {
symlink("/", "/tmp/rhimage");
symlink("/", "/tmp/image");
# if defined(__alpha__)
kernel = findKernel();
if (kernel)
execl("/usr/bin/runinstall2", "/usr/bin/runinstall2",
"--method", "cdrom", "--kernel", kernel,
isRescue ? "--rescue" : NULL, NULL);
else
execl("/usr/bin/runinstall2", "/usr/bin/runinstall2",
"--method", "cdrom",
isRescue ? "--rescue" : NULL, NULL);
# else
execl("/usr/bin/runinstall2", "/usr/bin/runinstall2",
"--method", "cdrom",
isRescue ? "--rescue" : NULL, NULL);
# endif
} else {
execl("/bin/install", "/bin/install",
isRescue ? "--rescue" : NULL, NULL);
}
exit(0);
}
while (!doShutdown) {
childpid = wait(&waitStatus);
if (childpid == installpid)
doShutdown = 1;
}
if (!WIFEXITED(waitStatus)) {
printf("install exited abnormally ");
if (WIFSIGNALED(waitStatus)) {
printf("-- recieved signal %d", WTERMSIG(waitStatus));
}
printf("\n");
} else {
doReboot = 1;
}
if (testing)
exit(0);
sync(); sync();
if (!testing) {
printf("sending termination signals..."); fflush(stdout);
kill(-1, SIGTERM);
sleep(2);
printf("done\n");
printf("sending kill signals..."); fflush(stdout);
kill(-1, SIGKILL);
sleep(2);
printf("done\n");
}
printf("unmounting filesystems...\n");
unmountFilesystems();
if (doReboot) {
printf("rebooting system\n");
sleep(2);
#ifdef __alpha__
reboot(RB_AUTOBOOT);
#else
reboot(0xfee1dead, 672274793, 0x1234567);
#endif
} else {
printf("you may safely reboot your system\n");
while (1);
}
}